/*
 * Title: WADS
 * Description: Web-based Auto flow Documents System
 * Copyright: 2007
 * Company: CoE
 * @author: Mr.Nattasan Wang-Aphisit
 * @version 1.1
 */

package wads.app;

import wads.drawing.line.CaseLink;
import wads.drawing.node.GroupNode;
import wads.drawing.node.DocumentNode;
import wads.drawing.node.DatabaseNode;
import wads.drawing.CaseShape;
import wads.drawing.node.CaseNode;
import wads.drawing.node.UserNode;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.PrinterJob;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Vector;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEdit;
import javax.swing.undo.UndoableEditSupport;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import wads.com.UserInfo;
import wads.com.WADTools;
import wads.database.DbConnector;
import wads.database.Derby;
import wads.drawing.node.GateNode;

public abstract class CaseEditor extends JFrame implements ActionListener, ItemListener {
  //File information
  private String currentFileName;
  private boolean fileModified;
  private boolean fileSaved;

  //aligment constants
  public static final int ALIGN_LEFT = 0;
  public static final int CENTER = 1;
  public static final int ALIGN_RIGHT = 2;
  public int currentAlignment = CENTER;

  /* WongVW cs5211, April, 2000*/
  // For toolbar based zooming in/out
  private int zoomPercent = 100;

  //font combo boxes
  private JComboBox fonts, sizes, styles;
  private int index = 0;
  private String fontchoice = "fontchoice";
  private int stChoice = 0;
  private String siChoice = "10";

//  protected static final Font LABEL_FONT = new Font("Courier", Font.PLAIN, 12);
  private CaseEditor ce;

  //Every editor will have a drawing area (a JPanel)
  //to be instantiated in its subclass
  private MessageBar messageBar;
  protected DrawPanel drawPanel = null;
  private ClipBoard clipBoard = null; //clipboard for cut and copy
  private boolean selectMode = true;
  private int currentTool;
  private PrinterJob printJob;
  private PageFormat defaultPF = new PageFormat();
  private Paper defaultPaper = new Paper();

  //Menu items that can be enable/disable
  //private JMenuItem addToProjectItem;
  private JMenuItem undoMenuItem;
  //JMenuItem redoMenuItem;
  protected JMenuItem cutMenuItem;
  protected JMenuItem copyMenuItem;
  protected JMenuItem pasteMenuItem;
  protected JMenuItem deleteMenuItem;
  protected JMenuItem selectallMenuItem;
  /*private JMenuItem alignLeftMenuItem;
  private JMenuItem alignRightMenuItem;
  private JMenuItem centerMenuItem;*/

  //Undo-Redo manager and support
  private UndoManager undoManager;
  private UndoableEditSupport undoSupport;

  //Menu actions
  private NewAction newAction;
  private OpenAction openAction;
  private SaveAction saveAction;
  private SaveAsAction saveAsAction;
  private PrintAction printAction;
  private PrintSetupAction printsetupAction;
  private ExitAction exitAction;
  
  protected DrawAction drawAction;
  protected DeleteNodeAction deleteNodeAction;
  protected DeleteLinkAction deleteLinkAction;
  //protected DeleteGroupAction deleteGroupAction;
  
  private UndoAction undoAction;
  private CutAction cutAction;
  private CopyAction copyAction;
  private PasteAction pasteAction;
  private DeleteAction deleteAction;
  private SelectAllAction selectallAction;
  
  private AboutAction aboutAction;
  private HelpAction helpAction;
  private CloseAction closeAction;

  private ZoomOutAction zoomOutAction;
  private ZoomInAction zoomInAction;
  //Zoom Buttons group
  private JRadioButtonMenuItem zoom50MenuItem = new JRadioButtonMenuItem("50%");
  private JRadioButtonMenuItem zoom75MenuItem = new JRadioButtonMenuItem("75%");
  private JRadioButtonMenuItem zoom100MenuItem = new JRadioButtonMenuItem("100%", true);
  private JRadioButtonMenuItem zoom125MenuItem = new JRadioButtonMenuItem("125%");
  private JRadioButtonMenuItem zoom150MenuItem = new JRadioButtonMenuItem("150%");

  private GetOrgAction getOrgAction;
  private ManageOrgAction manageOrgAction;

  private UserInfo PUUserInfo;
  private UserInfo RUUserInfo;
  //private MySql db;
  private Derby db;

  //Method for debug purpose
  public void pauseForKey(){
    System.out.println("Press any key to continue");
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    try {
      br.readLine();
    }
    catch(IOException e) {
      System.out.println("Exception thrown from CaseEditor.pauseForKey()");
      e.printStackTrace();
    }
  }

  public CaseEditor(String title){
    super(title);
    ce = this;

    //Query users data from database
    //PUUserInfo = WADTools.loadUsers("pu");
    //RUUserInfo = WADTools.loadUsers("ru");
    
    try {
        //db = new MySql();
        db = new Derby(Derby.EMBEDDED_FRAMEWORK);
        PUUserInfo = db.loadUsers(DbConnector.POWER_USER);
        RUUserInfo = db.loadUsers(DbConnector.RESTRICT_USER);
    }
    catch(Exception e) {
        System.err.println(e.getMessage());
        System.err.println("Database cannot load.");
    }

    //Init file information
    initFileInfo();

    //Initalize the undo.redo system
    initUndoRedoSystem();

    //Register for short cut keys
    registerKeys();

    //Listen for frame closing
    addWindowListener(new WindowCloser());
    
    //Get Printer Job
    printJob = PrinterJob.getPrinterJob();
    defaultPaper.setImageableArea(21.6, 21.6, 568.8000000000001, 748.8000000000001);
    defaultPF.setPaper(defaultPaper);
    //printJob.setPrintable(drawPanel, defaultPF);

    // Draw DocumentNode
  }

  public JScrollPane initScrollPanel(DrawPanel dp){
    //Create a scroll panel holding drawPanel
    JScrollPane scrollPane = new JScrollPane();
    scrollPane.setViewportView(dp);
    this.getContentPane().add(scrollPane,"Center");
    return scrollPane;
  }

  public void setAlignment(int alignment){
    this.currentAlignment = alignment;
  }

  public int getAlignment(){
    return this.currentAlignment;
  }

  @Override
  public void itemStateChanged(ItemEvent e){
    if( e.getStateChange() != ItemEvent.SELECTED ){
      return;
    }

    Object list = e.getSource();

    if(list == fonts){
      fontchoice = (String)fonts.getSelectedItem();
    }
    else if(list == styles){
      index = styles.getSelectedIndex();
      stChoice = index;
    }
    else{
      siChoice = (String)sizes.getSelectedItem();
    }

    drawPanel.changeFont(fontchoice, stChoice, siChoice);
    drawPanel.repaint();
  }

    /**
     * @return the PUUserInfo
     */
    public UserInfo getPUUserInfo() {
        return PUUserInfo;
    }

    /**
     * @param PUUserInfo the PUUserInfo to set
     */
    public void setPUUserInfo(UserInfo PUUserInfo) {
        this.PUUserInfo = PUUserInfo;
    }

    /**
     * @return the RUUserInfo
     */
    public UserInfo getRUUserInfo() {
        return RUUserInfo;
    }

    /**
     * @param RUUserInfo the RUUserInfo to set
     */
    public void setRUUserInfo(UserInfo RUUserInfo) {
        this.RUUserInfo = RUUserInfo;
    }

    /**
     * @return the db
     */
    public Derby getDb() {
        return db;
    }

    /**
     * @param db the db to set
     */
    public void setDb(Derby db) {
        this.db = db;
    }
  //inner Class MessageBar
  public class MessageBar {
    private JLabel helpLabel;
    private JLabel diagramNameLabel;
    private JLabel dynaMsgLabel;
    private JLabel wrkMsgLabel;

    public MessageBar(JFrame frame){
      //Create a message bar
      JPanel messageBar = new JPanel();
      messageBar.setLayout(new FlowLayout(FlowLayout.LEFT, 1, 0));
      messageBar.setSize(2500, 60);

      //Create label font
      // Font labelFont = new Font("C",Font.PLAIN,12);

      //Add status label to message bar
      helpLabel = new JLabel("For Help, press F1") ;
//      helpLabel.setFont(LABEL_FONT);
      helpLabel.setBorder(BorderFactory.createLoweredBevelBorder());
      messageBar.add(helpLabel);

      //Add dynamic message
      dynaMsgLabel = new JLabel("              ");
      dynaMsgLabel.setBorder(BorderFactory.createLoweredBevelBorder());
//      dynaMsgLabel.setFont(LABEL_FONT);
      messageBar.add(dynaMsgLabel);

      //Add project name label to message bar
      diagramNameLabel = new JLabel("Document Name: Untitled");
      diagramNameLabel.setBorder(BorderFactory.createLoweredBevelBorder());
//      diagramNameLabel.setFont(LABEL_FONT);
      diagramNameLabel.setSize(1500, 60);
      messageBar.add(diagramNameLabel);
      
      //Add Working Statusbar to message bar
      wrkMsgLabel = new JLabel("                          ");
      wrkMsgLabel.setBorder(BorderFactory.createLoweredBevelBorder());
//      wrkMsgLabel.setFont(LABEL_FONT);
      messageBar.add(wrkMsgLabel);

      frame.getContentPane().add(messageBar, "South");
    }

    public void setDiagramNameLabel(String name){
      diagramNameLabel.setText("Document Name: " + name);
    }

    public void setDynaMsgLabel(String name){
      dynaMsgLabel.setText(name);
    }
    
    public void setWorkingMsgLabel(String msg, Color txtColor) {
      wrkMsgLabel.setForeground(txtColor);
      wrkMsgLabel.setText(msg);
    }
  }// end MessageBar Class

  public void initMessageBar(){
    messageBar = new MessageBar(this);
  }

  public void initToolBars(JToolBar editorToolBar){
    //Add Main Application Toolbar
    JPanel toolBarsPanel = new JPanel();
    toolBarsPanel.setLayout(new BorderLayout());
    getContentPane().add(toolBarsPanel, "North");

    CommonToolBar commonToolBar = new CommonToolBar();

    AbstractAction actions[] = new AbstractAction[CommonToolBar.NO_OF_BUTTONS];
    actions[0] = newAction;
    actions[1] = openAction;
    actions[2] = saveAction;
    actions[3] = copyAction;
    actions[4] = cutAction;
    actions[5] = pasteAction;
    actions[6] = zoomInAction;
    actions[7] = zoomOutAction;

    commonToolBar.addActionListeners(actions);
    toolBarsPanel.add(commonToolBar, "North");
    toolBarsPanel.add(editorToolBar, "Center");
  }

  public void initMenus() {
    JMenuBar mb = new JMenuBar();
    this.setJMenuBar(mb);

    JMenu fileMenu = new JMenu("File");
//    fileMenu.setFont(LABEL_FONT);
    mb.add(fileMenu);

    newAction = new NewAction();
    JMenuItem newItem = new JMenuItem("New File            Ctrl+N", new ImageIcon("images/new.png"));
//    newItem.setFont(LABEL_FONT);
    newItem.addActionListener(newAction);
    fileMenu.add(newItem);
    newItem.setEnabled(true);

    openAction = new OpenAction();
    JMenuItem openItem = new JMenuItem("Open File          Ctrl+O", new ImageIcon("images/open.png"));
//    openItem.setFont(LABEL_FONT);
    openItem.addActionListener(openAction);
    fileMenu.add(openItem);
    openItem.setEnabled(true);

    fileMenu.addSeparator();

    saveAction = new SaveAction();
    JMenuItem saveItem = new JMenuItem("Save                  Ctrl+S", new ImageIcon("images/save.png"));
//    saveItem.setFont(LABEL_FONT);
    saveItem.addActionListener(saveAction);
    fileMenu.add(saveItem);
    saveItem.setEnabled(true);

    saveAsAction = new SaveAsAction();
    JMenuItem saveAsItem = new JMenuItem("Save As...         Alt+S", new ImageIcon("images/nullicon.gif"));
//    saveAsItem.setFont(LABEL_FONT);
    saveAsItem.addActionListener(saveAsAction);
    fileMenu.add(saveAsItem);
    saveAsItem.setEnabled(true);

    fileMenu.addSeparator();

    closeAction = new CloseAction();
    JMenuItem closeItem = new JMenuItem("Close", new ImageIcon("images/nullicon.gif"));
//    closeItem.setFont(LABEL_FONT);
    closeItem.addActionListener(closeAction);
    fileMenu.add(closeItem);
    closeItem.setEnabled(true);

    fileMenu.addSeparator();

    printAction = new PrintAction();
    JMenuItem printItem = new JMenuItem("Print                   Ctrl+P", new ImageIcon("images/print.png"));
//    printItem.setFont(LABEL_FONT);
    printItem.addActionListener(printAction);
    fileMenu.add(printItem);
    printItem.setEnabled(true);
    
    printsetupAction = new PrintSetupAction();
    JMenuItem printsetupItem = new JMenuItem("Page Setup...", new ImageIcon("images/nullicon.gif"));
//    printsetupItem.setFont(LABEL_FONT);
    printsetupItem.addActionListener(printsetupAction);
    fileMenu.add(printsetupItem);
    printsetupItem.setEnabled(true);

    fileMenu.addSeparator();

    exitAction = new ExitAction();
    JMenuItem exitItem = new JMenuItem("Quit                    Ctrl+Q", new ImageIcon("images/nullicon.gif"));
//    exitItem.setFont(LABEL_FONT);
    exitItem.addActionListener(exitAction);
    fileMenu.add(exitItem);
    exitItem.setEnabled(true);

    //Create edit menu and add edit menu to menu bar
    JMenu editMenu = new JMenu("Edit");
//    editMenu.setFont(LABEL_FONT);
    mb.add(editMenu);

    undoAction = new UndoAction();
    undoMenuItem = new JMenuItem("Undo                  Ctrl+Z", new ImageIcon("images/nullicon.gif"));
//    undoMenuItem.setFont(LABEL_FONT);
    undoMenuItem.addActionListener(undoAction);
    editMenu.add(undoMenuItem);
    undoMenuItem.setEnabled(true);

    drawAction = new DrawAction();

    cutAction = new CutAction();
    cutMenuItem = new JMenuItem("Cut                     Ctrl+X", new ImageIcon("images/cut.png"));
//    cutMenuItem.setFont(LABEL_FONT);
    cutMenuItem.addActionListener(cutAction);
    editMenu.add(cutMenuItem);
    cutMenuItem.setEnabled(true);

    copyAction = new CopyAction();
    copyMenuItem = new JMenuItem("Copy                  Ctrl+C", new ImageIcon("images/copy.png"));
//    copyMenuItem.setFont(LABEL_FONT);
    copyMenuItem.addActionListener(copyAction);
    editMenu.add(copyMenuItem);
    copyMenuItem.setEnabled(true);

    pasteAction = new PasteAction();
    pasteMenuItem = new JMenuItem("Paste                 Ctrl+V", new ImageIcon("images/paste.png"));
//    pasteMenuItem.setFont(LABEL_FONT);
    pasteMenuItem.addActionListener(pasteAction);
    editMenu.add(pasteMenuItem);
    pasteMenuItem.setEnabled(false);

    deleteNodeAction = new DeleteNodeAction();
    deleteLinkAction = new DeleteLinkAction();
    //deleteGroupAction = new DeleteGroupAction();

    deleteAction = new DeleteAction();
    deleteMenuItem = new JMenuItem("Delete                Del", new ImageIcon("images/delete.png"));
//    deleteMenuItem.setFont(LABEL_FONT);
    deleteMenuItem.addActionListener(deleteAction);
    editMenu.add(deleteMenuItem);
    deleteMenuItem.setEnabled(true);
    
    selectallAction = new SelectAllAction();
    selectallMenuItem = new JMenuItem("Select All          Ctrl+A", new ImageIcon("images/nullicon.gif"));
//    selectallMenuItem.setFont(LABEL_FONT);
    selectallMenuItem.addActionListener(selectallAction);
    editMenu.add(selectallMenuItem);
    selectallMenuItem.setEnabled(true);

    //Create tool menu
    JMenu toolMenu = new JMenu("Tools");
//    toolMenu.setFont(LABEL_FONT);

    //Add view menu to menu bar
    mb.add(toolMenu);

    //Create zoom submenu
    JMenu zoomSubMenu = new JMenu("Zoom");
//    zoomSubMenu.setFont(LABEL_FONT);

    //Create zoom submenu items
    ButtonGroup zoomGroup = new ButtonGroup();

    // RadioButton code from Khoo Yong Bing, April 2000.
    zoom50MenuItem.addActionListener(this);
    zoomSubMenu.add(zoom50MenuItem);
    zoomGroup.add(zoom50MenuItem);

    zoom75MenuItem.addActionListener(this);
    zoomSubMenu.add(zoom75MenuItem);
    zoomGroup.add(zoom75MenuItem);

    zoom100MenuItem.addActionListener(this);
    zoomSubMenu.add(zoom100MenuItem);
    zoomGroup.add(zoom100MenuItem);

    zoom125MenuItem.addActionListener(this);
    zoomSubMenu.add(zoom125MenuItem);
    zoomGroup.add(zoom125MenuItem);

    zoom150MenuItem.addActionListener(this);
    zoomSubMenu.add(zoom150MenuItem);
    zoomGroup.add(zoom150MenuItem);

    //Add zoom submenu to view menu
    toolMenu.add(zoomSubMenu);

    //Create grid lines sub menu
    JMenu gridSubMenu = new JMenu("Grid");
//    gridSubMenu.setFont(LABEL_FONT);

    //Create snap to grid menu item
    JCheckBoxMenuItem snapToGridItem = new JCheckBoxMenuItem("Snap to Grid");
//    snapToGridItem.setFont(LABEL_FONT);
    snapToGridItem.addActionListener(this);
    gridSubMenu.add(snapToGridItem);

    //Create show grid-lines menu item
    JCheckBoxMenuItem viewGridItem = new JCheckBoxMenuItem("Show Grid");
//    viewGridItem.setFont(LABEL_FONT);
    viewGridItem.addActionListener(this);
    gridSubMenu.add(viewGridItem);

    //Add grid lines submenu to view menu
    toolMenu.add(gridSubMenu);

    toolMenu.addSeparator();

    getOrgAction = new GetOrgAction();
    JMenuItem getOrgMenuItem = new JMenuItem("Import Organization from File");
//    getOrgMenuItem.setFont(LABEL_FONT);
    getOrgMenuItem.addActionListener(getOrgAction);
    getOrgMenuItem.setEnabled(false);

    toolMenu.add(getOrgMenuItem);

    //Create WAD Menu
    JMenu WADMenu = new JMenu("WADS");
//    WADMenu.setFont(LABEL_FONT);
    mb.add(WADMenu);

    manageOrgAction = new ManageOrgAction();
    JMenuItem manageOrgItem = new JMenuItem("Ctrl-W");
//    manageOrgItem.setFont(LABEL_FONT);
    manageOrgItem.addActionListener(manageOrgAction);
    manageOrgItem.setEnabled(false);
    manageOrgItem.setVisible(false);

    /* WongVW start */
    zoomInAction = new ZoomInAction();
    zoomOutAction = new ZoomOutAction();
    /* WongVW end */

    JMenu helpMenu = new JMenu("Help");
//    helpMenu.setFont(LABEL_FONT);
    mb.add(helpMenu);

    helpAction = new HelpAction();
    JMenuItem helpTextMenuItem = new JMenuItem("Help Contents");
//    helpTextMenuItem.setFont(LABEL_FONT);
    helpTextMenuItem.addActionListener(helpAction);
    //helpTextMenuItem.setEnabled(false);
    helpMenu.add(helpTextMenuItem);

    aboutAction = new AboutAction();
    JMenuItem aboutItem = new JMenuItem("About Us");
//    aboutItem.setFont(LABEL_FONT);
    aboutItem.addActionListener(aboutAction);
    aboutItem.setEnabled(true);
    helpMenu.add(aboutItem);

    //Init menu item status
    initMenuStatus();
  } //end of initMenus

  /* Initalise the user interface of case editor */
  public void initUI(JToolBar editorToolBar, DrawPanel editorDrawPanel){
    //Keep references
    drawPanel = editorDrawPanel;

    //Init the menus
    initMenus();

    //Initialize toolbars
    initToolBars(editorToolBar);

    //Create a scroll panel holding drawPanel
    initScrollPanel(editorDrawPanel);

    //Create message bar to editor
    initMessageBar();

    //initialize keys
    registerKeys();
  }

  public void initMenuStatus(){
    //The first four commands are disabled initially
    undoMenuItem.setEnabled(false);
    cutMenuItem.setEnabled(false);
    copyMenuItem.setEnabled(false);
    pasteMenuItem.setEnabled(false);
    deleteMenuItem.setEnabled(false);
  }

  public void initFileInfo(){
    setCurrentFileName(null);
    fileModified = false;
    fileSaved = false;
  }

  public void setCurrentFileName(String fileName){
    currentFileName = fileName;
    if ((messageBar!=null) && (fileName != null))
      messageBar.setDiagramNameLabel(fileName);
  }

  protected void initUndoRedoSystem(){
    undoManager = new UndoManager();
    undoSupport = new UndoableEditSupport();
    undoSupport.addUndoableEditListener(new UndoAdapter());
  }

  /* Register the shortcut keys */
  protected void registerKeys(){
    /* List of shortcut keys in CaseEditor:
    File
      New     - Ctrl+N
      Open    - Ctrl+O
      Save    - Ctrl+S
      Save As - Ctrl+A
      Print   - Ctrl+P
      Exit    - Ctrl+Q

    Edit
      Undo   - Ctrl+Z
      Cut    - Ctrl+X
      Copy   - Ctrl+C
      Paste  - Ctrl-V
      Delete - Del

      Total No of shortcut keys : 11
    */

    if (drawPanel == null) return;

    //New: Ctrl+N
    drawPanel.registerKeyboardAction(newAction,
      KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);

    //Open: Ctrl+O
    drawPanel.registerKeyboardAction(openAction,
      KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);

    //Save: Ctrl+S
    drawPanel.registerKeyboardAction(saveAction,
      KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);

    //Save As: Ctrl+A
    drawPanel.registerKeyboardAction(saveAsAction,
      KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.ALT_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);

    //Print: Ctrl+P
    drawPanel.registerKeyboardAction(printAction,
      KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);

    //Quit: Ctrl+Q
    drawPanel.registerKeyboardAction(exitAction,
      KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);

    //Undo: Ctrl+Z
    drawPanel.registerKeyboardAction(undoAction,
      KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);

    //Cut: Ctrl+X
    drawPanel.registerKeyboardAction(cutAction,
      KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);

    //Copy: Ctrl+C
    drawPanel.registerKeyboardAction(copyAction,
      KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);

    //Paste: Ctrl+V
    drawPanel.registerKeyboardAction(pasteAction,
      KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);

    //Delete: Del
    drawPanel.registerKeyboardAction(deleteAction,
      KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0, false), JComponent.WHEN_IN_FOCUSED_WINDOW);
    
    //Select All: Ctrl+A
    drawPanel.registerKeyboardAction(selectallAction,
        KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
    
    //Help: F1
    drawPanel.registerKeyboardAction(helpAction,
        KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0, false), JComponent.WHEN_IN_FOCUSED_WINDOW);

  } //end registerKeys

  @Override
  public void actionPerformed(ActionEvent evt){
    JMenuItem mi = (JMenuItem) evt.getSource();

    String commandName = mi.getActionCommand();

    if (commandName.equals("50%")) zoom(50);
    else if (commandName.equals("75%")) zoom(75);
    else if (commandName.equals("100%")) zoom(100);
    else if (commandName.equals("125%")) zoom(125);
    else if (commandName.equals("150%")) zoom(150);
    else if (commandName.equals("Snap to Grid")) {
      drawPanel.setSnapToGrid(((JCheckBoxMenuItem)mi).getState());
      drawPanel.repaint();
    }else if (commandName.equals("Show Grid")) {
      drawPanel.setDrawGrid(((JCheckBoxMenuItem)mi).getState());
      drawPanel.repaint();
      drawPanel.drawGrid();
    }
  }

  protected void zoom(int percent){
    //Zoom the drawing panel at a specified percentage
    drawPanel.zoom(percent);
  }

  public boolean isSelectMode(){
    return selectMode;
  }

  @Override
  public Dimension getPreferredSize(){
    return new Dimension(400, 400);
  }

  public DrawPanel getDrawPanel(){
    return drawPanel;
  }
  
  public String getCurrentFileName(){
    return currentFileName;
  }

  public int getCurrentTool(){
    return currentTool;
  }

  public void setCurrentTool(int toolCode){
    currentTool = toolCode;
    drawPanel.setCurrentToolCursor(toolCode);
  }

  public void setFileModified(boolean result){
    fileModified = result;
  }

  public boolean isFileModified(){
    return fileModified;
  }

  public void setFileSaved(boolean result){
    fileSaved = result;
  }

  public boolean isFileSaved(){
    return fileSaved;
  }

  public void refreshUndoRedo(){
    //Refresh undo menu item
    undoMenuItem.setEnabled(undoManager.canUndo());

    //Refresh redo menu item
    //redoMenuItem.setEnabled(undoManager.canRedo());
  }

  protected void zoomIn() {
    if(zoomPercent < 150) {
      zoomPercent += 25;
      zoom(zoomPercent);
      setZoomSelected();
    }
  }

  protected void zoomOut() {
    if(zoomPercent > 50) {
      zoomPercent -= 25;
      zoom(zoomPercent);
      setZoomSelected();
    }
  }

  public void setDynaMsg(String msg) {
    messageBar.setDynaMsgLabel(msg);
  }
  
  public void setWrkMsg(String msg, Color msgColor) {
    messageBar.setWorkingMsgLabel(msg, msgColor);
  }

  public void updateMenu() {
    //Undo,Cut,Copy,Paste,Del
    //Undo only if undoManager can undo
    //Cut,Copy,Delete only if item is selected
    //Paste only if clipboard is not null
    undoMenuItem.setEnabled(undoManager.canUndo());
    boolean isSelected = !drawPanel.getSelectedShapes().isEmpty();
    cutMenuItem.setEnabled(isSelected);
    copyMenuItem.setEnabled(isSelected);
    deleteMenuItem.setEnabled(isSelected);
    boolean hasCopied = (clipBoard != null);
    pasteMenuItem.setEnabled(hasCopied);
  }

  public boolean warnUserToSave(Object source,int type, String commandString){
    int response = JOptionPane.showConfirmDialog(CaseEditor.this,
      "Do you want to save the current diagram file?");

    if(response == JOptionPane.YES_OPTION){
      CaseEditor.this.saveAction.actionPerformed(
        new ActionEvent(source, type, commandString));
      return true;
    }
    else if(response == JOptionPane.NO_OPTION){
      return true;
    }
    else if(response == JOptionPane.CANCEL_OPTION){
      return false;
    }
    else if(response == JOptionPane.CLOSED_OPTION){
      return false;
    }
    else if(CaseEditor.this.isFileSaved()){
      return true;
    }
    else{
      return false;
    }
  }

  public boolean openFile(String fileName) {
    String cfileName;
    try{
      ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));
      System.out.println("Reading Diagram file ...");
      cfileName = fileName.substring(fileName.lastIndexOf("\\")+1);
      System.out.println(cfileName);

      //Read from file the number of objects to read in
      int size = in.readInt();

      //Loop to read all objects in
      for(int i=0; i<size; i++) {
        Object obj = in.readObject();
        drawPanel.addElementToShapesDrawn((CaseShape)obj);
        System.out.println(obj);
      }

      in.close();

      //Update screen
      drawPanel.repaint();

      //Init file info
      setCurrentFileName(cfileName);
      fileSaved = false;
      fileModified = false;
      return true;
    }
    catch (Exception e) {
      JOptionPane.showMessageDialog(null,
        "File specified cannot be opened.\nPlease check that filename specified is valid.",
        "Alert", JOptionPane.ERROR_MESSAGE);
      drawPanel.clearShapesDrawn();
      drawPanel.addDocShape(new DocumentNode(new Point(50, 50)));
      drawPanel.repaint();
      System.err.println("Error on opening file, restart to initialize state.");
    }

    return false;
  }
  
  public boolean openXPDL(String file) {
    try {
      org.w3c.dom.Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(file);
      return true;
    }
    catch (SAXException ex) {
      java.util.logging.Logger.getLogger(CaseEditor.class.getName()).log(Level.SEVERE, null, ex);
    }
    catch (IOException ex) {
      java.util.logging.Logger.getLogger(CaseEditor.class.getName()).log(Level.SEVERE, null, ex);
    }
    catch (ParserConfigurationException ex) {
      java.util.logging.Logger.getLogger(CaseEditor.class.getName()).log(Level.SEVERE, null, ex);
    }
    
    return false;
  }

  public boolean saveFile(String fileName) {
    String cfileName;
    Vector shapesDrawn = drawPanel.getShapeDrawn();
    int size = shapesDrawn.size();
    try {
      ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName));
      cfileName = fileName.substring(fileName.lastIndexOf("\\")+1);

      //Write to file the number of objects to be written
      oos.writeInt(size);

      for (int i=0; i<size; i++){
        oos.writeObject(shapesDrawn.elementAt(i));
        System.out.println(shapesDrawn.elementAt(i));
      }

      System.out.println("Saved file ...");
      oos.close();

      //Keep this file name if saved successfully
      setCurrentFileName(cfileName);
      setTitle("WADS 1.1 - "+currentFileName);
      return true;
    }
    catch(Exception e) {
      e.printStackTrace();
      JOptionPane.showMessageDialog(null,
        "File specified cannot be saved.\nPlease check that filename specified is valid.",
        "Alert", JOptionPane.ERROR_MESSAGE);
      return false;
    }
  }// end of saveFile()

  //WongVW Add
  /*public void generateDocument(){
    Vector shapesDrawn = drawPanel.shapesDrawn;
    int size = shapesDrawn.size();

    CaseEditorDocDialog dlg = new CaseEditorDocDialog();
    for(int i=0; i<size; i++){
      Object obj = shapesDrawn.elementAt(i);
      if(!(obj instanceof CaseLink))
        dlg.appendNodeDoc((CaseNode)obj);
    }
       
    dlg.show();
  }*/

  //inner Class UndoAdapter
  protected class UndoAdapter implements UndoableEditListener{
    @Override
    public void undoableEditHappened(UndoableEditEvent evt){
      UndoableEdit edit = evt.getEdit();
      undoManager.addEdit(edit);

      //Refresh undo menu item
      undoMenuItem.setEnabled(undoManager.canUndo());
    }
  }// end of UndoAdapter Class

  //inner Class DrawNodeEdit
  protected class DrawNodeEdit extends AbstractUndoableEdit{
//    private static final long serialVersionUID = 5029148363200458733L;
    
    private DrawPanel drawPanel;
    private CaseNode node;
    private int lastPosition;

    public DrawNodeEdit(DrawPanel dp, CaseNode cn, int lastPos){
      drawPanel = dp;
      node = cn;
      lastPosition = lastPos;
      if(false)
        System.out.println(lastPosition);
    }

    @Override
    public void undo() throws CannotUndoException{
      //Delete the node
      drawPanel.delete(node);

      //Update screen after deletion
      drawPanel.repaint();
    }

    @Override
    public void redo() throws CannotRedoException{
      //Note : These steps are to ensure that the shape is
      //redrawn at the same layer as that previously.
      //The Redo is disabled for the time being as there might not
      //be sufficient time to put up the redo for the other edit functions.
      //It needs the other redos to be working to have a consistent
      //Redo framework.

      /*
      //1.add shape at the last ith position in the vector
      drawPanel.addNewShapeAt(node,lastPosition);

      //2.repaint
      drawPanel.repaint();
      */
    }

    @Override
    public boolean canUndo(){
      return true;
    }

    @Override
    public boolean canRedo(){
      return false;
    }

    @Override
    public String getPresentationName(){
      return "Draw Node";
    }
  }// end DrawNodeEdit - internal class of CaseEditor class

  //inner Class DrawLinkEdit
  protected class DrawLinkEdit extends AbstractUndoableEdit{
//    private static final long serialVersionUID = 6227002909271709384L;
    
    private DrawPanel drawPanel;
    private CaseLink link;
    private int lastPosition;

    public DrawLinkEdit(DrawPanel dp, CaseLink cl, int lastPos){
      drawPanel = dp;
      link = cl;
      lastPosition = lastPos;
      if(false)
        System.out.println(lastPosition);
    }

    @Override
    public void undo() throws CannotUndoException{
      //Delete the link
      drawPanel.delete(link);

      //Update screen after deletion
      drawPanel.repaint();
    }

    @Override
    public void redo() throws CannotRedoException{
      //Note : These steps are to ensure that the shape is redrawn at the
      //same layer as that previously
      //The Redo is disabled for the time being as there might not
      //be sufficient time to put up the redo for the other
      //edit functions.
      //It needs the other redos to be working to have a consistent
      //Redo framework.

      /*
      //1.add shape at the last ith position in the vector
      drawPanel.addNewShapeAt(link,lastPosition);

      //2.repaint
      drawPanel.repaint();
      */
    }

    @Override
    public boolean canUndo(){
      return true;
    }

    @Override
    public boolean canRedo(){
      return false;
    }

    @Override
    public String getPresentationName(){
      return "Draw Link";
    }

  }// end DrawLinkEdit - internal class of CaseEditor class
  
  protected class DrawGroupEdit extends AbstractUndoableEdit{
//    private static final long serialVersionUID = -8810851634290466414L;

    private DrawPanel drawpanel;
    private GroupNode group;
    private int lastpos;

    public DrawGroupEdit(DrawPanel dp, GroupNode cg, int index){
      drawpanel = dp;
      group = cg;
      lastpos = index;
      if(false)
        System.out.println(lastpos);
    }
    
    @Override
    public void undo() throws CannotUndoException{
      //Delete the link
      drawpanel.delete(group);

      //Update screen after deletion
      drawpanel.repaint();
    }

    @Override
    public void redo() throws CannotRedoException{
      //Note : These steps are to ensure that the shape is redrawn at the
      //same layer as that previously
      //The Redo is disabled for the time being as there might not
      //be sufficient time to put up the redo for the other
      //edit functions.
      //It needs the other redos to be working to have a consistent
      //Redo framework.


      //1.add shape at the last ith position in the vector
      //drawPanel.addNewShapeAt(link, lastPosition);

      //2.repaint
      //drawPanel.repaint();
    }

    @Override
    public boolean canUndo(){
      return true;
    }

    @Override
    public boolean canRedo(){
      return false;
    }

    @Override
    public String getPresentationName(){
      return "Draw Group";
    }
  }

  //inner Class DeleteNodeEdit
  protected class DeleteNodeEdit extends AbstractUndoableEdit{
//    private static final long serialVersionUID = -5276659791509439663L;
    
    private CaseNode node;
    private int lastPosition;

    //The node is cloned here and thisclone copys the references
    //of the connectedLinks also
    //This is to avoid trouble of reinstalling the links
    public DeleteNodeEdit(CaseNode node, int lastPosition){
      this.node = node;
      this.lastPosition = lastPosition;
    }

    @Override
    public void undo() throws CannotUndoException {
      //Add the node back to shapesDrawn
      drawPanel.addNewShapeAt(node, lastPosition);

      //Update screen after undeletion
      repaint();
    }
    @Override
    public void redo() throws CannotRedoException {
      //Set up a look to redo each deletion
    }

    @Override
    public boolean canUndo(){
      return true;
    }

    @Override
    public boolean canRedo(){
      return false;
    }

    @Override
    public String getPresentationName(){
      return "Delete Node";
    }
  }// end DeleteNodeEdit class - internal class of CaseEditor

  protected class DeleteLinkEdit extends AbstractUndoableEdit{
//    private static final long serialVersionUID = 6415192100181262065L;
    
    private CaseLink link;
    private int lastPosition;

    public DeleteLinkEdit(CaseLink link, int lastPosition){
      this.link = link;
      this.lastPosition = lastPosition;
    }

    @Override
    public void undo() throws CannotUndoException{
      //Refresh link as the node connected might have changed
      // (eg. resize/moved)
      link.refresh();

      //Obtain anchored nodes
      CaseNode startNode = link.getStartNode();
      CaseNode endNode = link.getEndNode();

      //Add link to the nodes
      //Warning : by adding the link back this way, we do not ensure
      //that the order of the links are drawn as previously.
      //Perhaps we should enable link to be add at a certain position
      //like the node. However, this would not propose a layering
      //problem as
      //believed intially because we did not restore the order
      //of link in connectedLinks as before they were deleted.
      //This is because as long as the link is restored at the
      //last position
      //within shapesDrawn, the layering problem will not appear.

      startNode.addConnectedLink(link);
      endNode.addConnectedLink(link);

      //Add link back to shapes drawn
      drawPanel.addNewShapeAt(link,lastPosition);

      //Update screen
      drawPanel.repaint();
    }

    @Override
    public void redo() throws CannotRedoException{
      //Set up a look to redo each deletion
    }

    @Override
    public boolean canUndo(){
      return true;
    }

    @Override
    public boolean canRedo(){
      return false;
    }

    @Override
    public String getPresentationName(){
      return "Delete Link";
    }
  }// end DeleteLinkEdit class - internal class of CaseEditor

  protected class PasteEdit extends AbstractUndoableEdit{
//    private static final long serialVersionUID = -3043961177993113168L;
    
    private ClipBoard clipBoard;
    private Vector shapesDrawn;
    private int firstElementPastedIndex;
    private int lastElementPastedIndex;

    public PasteEdit(ClipBoard cb, Vector shapes){
      this.clipBoard = cb;
      this.shapesDrawn = shapes;
      this.firstElementPastedIndex = shapes.size();
      this.lastElementPastedIndex = this.firstElementPastedIndex +
        clipBoard.size() - 1;
    }

    @Override
    public void undo() throws CannotUndoException{
      /*Remarked because removeRange method is not working in
      JDK1.2 Beta4.  This is a bug in beta4. This bug does not
      exists in beta4 or in FCS.
      Remove the pasted elements from shapesDrawn
      Add 1 to the lastElementPastedIndex because the
      toIndex of the range is not inclusive.
      See documentation for Vector.

      shapesDrawn.removeRange(firstElementPastedIndex,
      lastElementPastedIndex+1);
      */
      //Since the method no longer works, we shall manually loop
      //through the vector to remove the elements

      //The reason of always removing the frist element is because
      //after every deletion the vector shrinks and so it is no longer
      //valid to delete object the next larger index. The object
      //previously at the next larger index has already being
      //shifed down towards 0 by -1 after every deletion.
      //This manual step could be removed once the JDK1.2FCS platform
      //is available on the working pc.

      for (int i=firstElementPastedIndex; i<=lastElementPastedIndex; i++){
        shapesDrawn.removeElementAt(firstElementPastedIndex);
      }

      //Update screen after removal
      drawPanel.repaint();
    }

    @Override
    public void redo() throws CannotRedoException {
    }

    @Override
    public boolean canUndo() {
      return true;
    }

    @Override
    public boolean canRedo() {
      return false;
    }

    @Override
    public String getPresentationName() {
      return "Paste";
    }
  }//end class PasteEdit - internal class of CaseEditor

  protected class UndoAction extends AbstractAction{
//    private static final long serialVersionUID = 5529775401615641426L;
    
    @Override
    public void actionPerformed(ActionEvent evt){
      if (undoManager.canUndo()){
        //Ask undoManager to perform undo
        undoManager.undo();

        //Refresh undo menu item
        undoMenuItem.setEnabled(undoManager.canUndo());
      }
    }
  }// end inner class UndoAction

  public class DrawAction extends AbstractAction{
//    private static final long serialVersionUID = -221635997897553648L;

    @Override
    public void actionPerformed(ActionEvent evt) {
      CaseShape shape = null;
      UndoableEdit edit = null;

      //Extract information from drawPanel
      shape = drawPanel.getCurrentShape();

      int index = drawPanel.getShapeDrawnIndex(shape);

      //Record the effect of action fo repsective shape type
      if (shape instanceof CaseNode)
        edit = new DrawNodeEdit(drawPanel, (CaseNode)shape, index);
      else if (shape instanceof CaseLink)
        edit = new DrawLinkEdit(drawPanel, (CaseLink)shape, index);
      else
        return;

      //Notify the listeners
      undoSupport.postEdit(edit);
    }
  }//end inner class DrawAction

  public class DeleteAction extends AbstractAction{
//    private static final long serialVersionUID = 1620652899894448905L;

    @Override
    public void actionPerformed(ActionEvent evt){
      //Start the CompoundEdit support
      undoSupport.beginUpdate();

      int size = drawPanel.getSelectedShapes().size();

      //Delete selected shapes
      for (int i=0;i<size;i++){
        //Obtain the selected shape
        CaseShape shape = (CaseShape)drawPanel.getSelectedShapes().elementAt(i);

        if(shape instanceof DocumentNode) {
          JOptionPane.showMessageDialog(CaseEditor.this, "This is Document, it can't be deleted.", "Document deleteion Warning", JOptionPane.WARNING_MESSAGE);
        }
        else if(shape instanceof DatabaseNode) {
          drawPanel.delete((CaseNode)shape);
        }
        else if(shape instanceof GroupNode) {
          for(int j=0;j<((GroupNode)shape).getNodes().size();j++){
            drawPanel.delete(((GroupNode)shape).getNodes().elementAt(j));
          }
          drawPanel.delete(((CaseNode)shape));
        }
        else if(shape instanceof UserNode) {
          //edit = new DeleteNodeEdit((CaseNode)shape,index);
          if(((UserNode)shape).isGroupMember())
            ((UserNode)shape).getGroupParent().removeNodeMember((UserNode)shape);

          drawPanel.delete((CaseNode)shape);
        }
        else if(shape instanceof GateNode) {
            drawPanel.delete((CaseNode)shape);
        }
        else if(shape instanceof CaseNode) {
            drawPanel.delete((CaseNode)shape);
        }
        else if(shape instanceof CaseLink) {
          //edit = new DeleteLinkEdit((CaseLink)shape,index);
          drawPanel.delete((CaseLink)shape);
        }
        else
          return;
      }

      //Remove selectedShapes from drawPanel
      //This should be done after the above notification else
      //the selectedShapes received by the listerner will be null.
      drawPanel.getSelectedShapes().removeAllElements();

      //Update screen after removing selected shapes
      drawPanel.repaint();

      //End CompoundEdit support
      undoSupport.endUpdate();

      //Update menu
      updateMenu();
    }
  }// end of internal class DeleteAction
  
  public class SelectAllAction extends AbstractAction{
//    private static final long serialVersionUID = 8798459086348164936L;

    @Override
    public void actionPerformed(ActionEvent evt){
      for(int i=0;i<drawPanel.getShapeDrawn().size();i++){
        drawPanel.selectShape(drawPanel.getShapeDrawn().elementAt(i));
        drawPanel.repaint();
      }
    }
  }

  public class DeleteNodeAction extends AbstractAction{
//    private static final long serialVersionUID = 2121525745703997498L;

    @Override
    public void actionPerformed(ActionEvent evt){
      if (evt.getSource() instanceof CaseNode){
        //Use source to pass the node reference
        CaseNode node = (CaseNode)evt.getSource();

        //Warning : This step is very order dependent. The node must not be removed
        //before this step is called else index = -1.
        //Should get caller to pass the index.

        //Obtain the position of node in shapesDrawn vector
        int index = drawPanel.getShapeDrawnIndex(node);

        //Note : The undo action of draw node cannot be undone
        //so the delete action caused by undo in draw node so
        //an undoEdit must not be created. This is detected if
        //undoSupport current updateLevel is not zero => a compound
        //edit has begun
        if (undoSupport.getUpdateLevel() > 0){
          //Creates an UndoableEdit to enable undo of deletion of link
          UndoableEdit edit = new DeleteNodeEdit(node, index);
          undoSupport.postEdit(edit);
        }
      }
    }
  }//end of internal class DeleteNodeAction

  public class DeleteLinkAction extends AbstractAction{
//    private static final long serialVersionUID = -6663539560482329446L;

    @Override
    public void actionPerformed(ActionEvent evt){
      if (evt.getSource() instanceof CaseLink){
        //Use source to pass the link reference
        CaseLink link = (CaseLink)evt.getSource();

        //Warning : This step is very order dependent. The link must not be removed
        //before this step is called else index = -1.
        //Should get caller to pass the index.

        //Obtain the position of link in shapesDrawn vector
        int index = drawPanel.getShapeDrawnIndex(link);

        if (undoSupport.getUpdateLevel() > 0){
          //Creates an UndoableEdit to enable undo of deletion of link
          UndoableEdit edit = new DeleteLinkEdit(link,index);

          undoSupport.postEdit(edit);
        }
      }
    }
  }//end of internal class DeleteLinkAction
  
  /*public class DeleteGroupAction extends AbstractAction{
    private static final long serialVersionUID = -3017084190783705796L;

    public void actionPerformed(ActionEvent evt){
      
    }
  }*/

  public class CopyAction extends AbstractAction{
//    private static final long serialVersionUID = -4645452618000034718L;

    @Override
    public void actionPerformed(ActionEvent evt){
      clipBoard = new ClipBoard();  //reinit clipboard
      Object origShape = null;
      int size = drawPanel.getSelectedShapes().size();

      if (size == 0) return;

/*  Copy : wanted to copy all nodes and those links that have
    their nodes (start and end nodes) selected.

    The algo for copy will be
    1. Clone all nodes in the selected shapes first
    2. Now clone links only if both it's start and end nodes are
       in the selected shapes.
    3. Recreate the links with the clone nodes

    To enable step 3, we must enable the link to know which is the
    clone nodes of the orginal nodes, so that it can now
    reference to the clones.  The way to do this is to keep
    a vector of clones corresponding to the selectedShapes,
    positioning the clones at same element index in the vector.
    However, this metthod wastes vector space as some elements
    are null.
    This might also have problem drawing using the clipboard
    if the draw routine does not know how to handle null objects.

    4. A layering problem may occur here. So we need to sort the
    clipboard according to shapesDrawn.

    The algorithm did not not work. So we back down to copy
    that can only copy nodes, like that in the old jcase.

    //Step 1: Clone all the nodes
    for (int i=0;i<size;i++){
      origShape = drawPanel.selectedShapes.elementAt(i);
      if (origShape instanceof CaseNode){
        CaseNode clonedNode = (CaseNode)
        ((CaseNode)(origShape)).clone();
        clipBoard.addElement(clonedNode);
      }
      else
        clipBoard.addElement(null);
      }

      //Step 2: Clone links that have both start and end nodes selected
      for (int i=0;i<size;i++){
        origShape = drawPanel.selectedShapes.elementAt(i);
        if (origShape instanceof CaseLink){
          //Get the original node references
          CaseNode startNode = ((CaseLink)origShape).getStartNode();
          CaseNode endNode = ((CaseLink)origShape).getEndNode();

          //Check if both start and end nodes are selected
          if ( drawPanel.selectedShapes.contains(startNode) &&
            drawPanel.selectedShapes.contains(endNode)){
            //Clone the link
            CaseLink clonedLink = (CaseLink)
            ((CaseLink)(origShape)).clone();

            //Get index position of start and end nodes of the link
            int startNodeIndex = drawPanel.selectedShapes.indexOf(startNode);
            int endNodeIndex = drawPanel.selectedShapes.indexOf(endNode);

            //Get the repsective cloned nodes
            CaseNode clonedStartNode = (CaseNode)clipBoard.elementAt(startNodeIndex);
            CaseNode clonedEndNode = (CaseNode)clipBoard.elementAt(endNodeIndex);

            //Create cloned link with clone nodes
            clonedLink.createLink(clonedStartNode, clonedEndNode);

            //Add cloned link to clipBoard
            clipBoard.addElement(clonedLink);
          }
        }
      }
*/ // end of the commented-out, non-functional code. Try another time

      //Clone only nodes - the simplistic copy method
      for (int i=0; i<size; i++){
        origShape = drawPanel.getSelectedShapes().elementAt(i);
        if (origShape instanceof CaseNode){
          CaseNode clonedNode = (CaseNode)((CaseNode)origShape).clone();
          clipBoard.addElement(clonedNode);
        }
      }

      //Enable Paste Menu Item
      pasteMenuItem.setEnabled(true);
    }
  }// end internal class CopyAction - inside CaseEditor

  public class PasteAction extends AbstractAction{
//    private static final long serialVersionUID = -1742861598810005511L;

    @Override
    public void actionPerformed(ActionEvent evt){
      //Paste the clipboard on the screen as they were last copied
      //This is done by adding the shapes in the clipBoard
      //to the shapesDrawn.
      //Note : Paste is an undoable action so a PasteUndoableEdit
      //is required.
      if (clipBoard != null){
        //Clone clipboard
        ClipBoard clipBoardClone = (ClipBoard)clipBoard.clone();
        Vector<CaseShape> cbcvector = (Vector<CaseShape>)clipBoardClone;

        //Create edit object
        PasteEdit pasteEdit = new PasteEdit(clipBoardClone, drawPanel.getShapeDrawn());

        //Add content of cloned clipboard to shapesDrawn
        drawPanel.addAllToShapesDrawn(cbcvector);

        //Set the shapes just pasted as the current selected shapes
        drawPanel.setSelectedShapes(cbcvector);

        //Update screen
        repaint();

        //Notify listerner for the overall deletion
        undoSupport.postEdit(pasteEdit);
      }
    }
  }// end of internal class PasteAction - inside CaseEditor

  public class CutAction extends AbstractAction{
//    private static final long serialVersionUID = -7446362059742997614L;

    @Override
    public void actionPerformed(ActionEvent evt){
      //First, activate copy
      copyAction.actionPerformed(null);

      //Next, activate delete
      deleteAction.actionPerformed(null);
    }
  }


  public class ClipBoard extends Vector {
//    private static final long serialVersionUID = -3773630050466011552L;

    //Does a deep copy of the clipboard vector
    @Override
    public Object clone(){
      Vector<Object> clonedVector = new Vector<Object>();
      clonedVector = (Vector<Object>)super.clone();

      for (int i=0; i < size(); i++){
        clonedVector.set(i, ((CaseShape)this.elementAt(i)).clone());
      }

      return clonedVector;
    }
  }

  public class NewAction extends AbstractAction {
//    private static final long serialVersionUID = -6330476416700038779L;

    @Override
    public void actionPerformed(ActionEvent evt){
      if((!drawPanel.isModified()) || (warnUserToSave(this,-1,"New"))){
        //Remove all shapes drawn and selections
        drawPanel.removeAll();

        //Update the menu bar status
        initMenuStatus();

        //Clear screen
        repaint();

        //Init file information
        initFileInfo();

        //Update menu items
        updateMenu();

        setFileModified(false);
        drawPanel.setModified(false);
        System.out.println("New Document");
        Point anchor = new Point(50,50);
        drawPanel.addDocShape(new DocumentNode(anchor));
      }
    }
  }


  public class CloseAction extends AbstractAction{
//    private static final long serialVersionUID = 4340368333269092846L;

    @Override
    public void actionPerformed(ActionEvent evt){
      if((!drawPanel.isModified()) || (warnUserToSave(this,-1,"New"))){
        //Remove all shapes drawn and selections
        drawPanel.removeAll();

        //Update the menu bar status
        initMenuStatus();

        //Clear screen
        repaint();

        //Init file information
        initFileInfo();

        //Update menu items
        updateMenu();

        setFileModified(false);
        drawPanel.setModified(false);
        // System.exit(0);
      }
    }
  }

   public class OpenAction extends AbstractAction{
//    private static final long serialVersionUID = 5594863371789809432L;

    @Override
    public void actionPerformed(ActionEvent evt){
      String cfileName;
      if((! drawPanel.isModified()) || (warnUserToSave(this,-1,"Open"))){
        //Show file dialog
        JFileChooser chooser = new JFileChooser(WADTools.DEFAULT_WDE_PATH);
        chooser.setMultiSelectionEnabled(false);
        //chooser.setFileFilter(new DiagramFilter(WADTools.DIAGRAM_FILE_EXTENSION));
        int returnVal = chooser.showOpenDialog(CaseEditor.this);

        //if Cancel is selected nothing to do
        if(returnVal != JFileChooser.APPROVE_OPTION)
          return;

        File selectedFile = chooser.getSelectedFile();
        if(selectedFile == null)
          return;

        String fileName = selectedFile.getPath();
        cfileName = fileName.substring(fileName.lastIndexOf("\\")+1);
        if((fileName==null)||(fileName.equals("")))
          return;

        drawPanel.clearShapesDrawn();
        if(openFile(fileName)){
           setCurrentFileName(cfileName);
        }
      }
    }
  }

  public class SaveAction extends AbstractAction{
//    private static final long serialVersionUID = 5050692062389856776L;

    @Override
    public void actionPerformed(ActionEvent evt) {
      if((currentFileName==null) || (currentFileName.equals(""))) {
        CaseEditor.this.saveAsAction.actionPerformed(evt);
      }
      else if(saveFile(currentFileName)) {
        drawPanel.setModified(false);
        setFileSaved(true);
      }
      else {
        //nothing to do
      }
    }
  }// end of SaveAction Class



  public class SaveAsAction extends AbstractAction{
//    private static final long serialVersionUID = 7288364759279301386L;

    @Override
    public void actionPerformed(ActionEvent evt){
      //Show file dialog
      JFileChooser chooser = new JFileChooser(WADTools.DEFAULT_WDE_PATH);
      chooser.setMultiSelectionEnabled(false);
      chooser.setFileFilter(new DiagramFilter(WADTools.DIAGRAM_FILE_EXTENSION));

      int returnVal = chooser.showSaveDialog(CaseEditor.this);
      if(returnVal != JFileChooser.APPROVE_OPTION){
        return;
      }

      File selectedFile = chooser.getSelectedFile();
      if(selectedFile == null) { return; }

      String fileName = selectedFile.getPath();
      if((fileName==null)||(fileName.equals(""))) return;

      // modify to add file extension 000127, JCM
      String ext = "." + WADTools.DIAGRAM_FILE_EXTENSION;
      if(fileName.toUpperCase().indexOf(ext.toUpperCase()) == -1)
        fileName = fileName + ext;
      // end modification to add file extension

      boolean saveResult = saveFile(fileName);
      setFileSaved(saveResult);
      if(saveResult) {
        drawPanel.setModified(false);
      }
    }
  }// end of SaveAsAction Class


  public class PrintAction extends AbstractAction{
//    private static final long serialVersionUID = 1667210031172386659L;

    @Override
    public void actionPerformed(ActionEvent evt){
      if(printJob.printDialog()){
        try{
          printJob.print();
        }
        catch(Exception ex){ ex.printStackTrace(); }
      }
    }
  }// end of PrintAction Class
  
  public class PrintSetupAction extends AbstractAction{
//    private static final long serialVersionUID = -8505266194419778588L;

    @Override
    public void actionPerformed(ActionEvent evt){
      printJob.setPrintable(drawPanel, printJob.pageDialog(defaultPF));
    }
  }//end of PrintSetupAction

  public class ExitAction extends AbstractAction {
//    private static final long serialVersionUID = -5604085003301644665L;

    @Override
    public void actionPerformed(ActionEvent evt){
      if ((!drawPanel.isModified()) || (warnUserToSave(this,-1,"Exit"))) {
        System.exit(0);
      }
    }
  }// end of ExitAction Class

  public class AboutAction extends AbstractAction {
//    private static final long serialVersionUID = -6127154708929251002L;

    @Override
    public void actionPerformed(ActionEvent evt) {
      new AboutDialog(CaseEditor.this);
    }
  }// end of AboutAction Class

  public class WindowCloser extends WindowAdapter {
    @Override
    public void windowClosing(WindowEvent e){
      //if ((!drawPanel.isModified()) || (warnUserToSave(this,-1,"Exit")))
      //{
        System.exit(0);
      //}
    }
  }// end of WindowCloser Class

  public class ZoomInAction extends AbstractAction{
//    private static final long serialVersionUID = -7531312022020137590L;

    @Override
    public void actionPerformed(ActionEvent evt){
      zoomIn();
    }
  }// end of ZoomInAction

  public class ZoomOutAction extends AbstractAction{
//    private static final long serialVersionUID = 8225144624193261216L;

    @Override
    public void actionPerformed(ActionEvent evt){
      zoomOut();
    }
  }// end of ZoomOutAction

  //inner Class GetOrgAction: No use in this time
  public class GetOrgAction extends AbstractAction{
//    private static final long serialVersionUID = 1530540391302817567L;

    @Override
    public void actionPerformed(ActionEvent evt){
      System.out.println("Change Organization");
    }
  }// end of GetOrgAction Class

  //inner Class ManageOrgAction: No use in this time
  public class ManageOrgAction extends AbstractAction{
//    private static final long serialVersionUID = -2465061053187648849L;

    @Override
    public void actionPerformed(ActionEvent evt){
      JOptionPane.showInputDialog("Organization Name");
    }
  }// end of ManageOrgAction

  //inner Class HelpAction: It's Unavailable NOW!!
  public class HelpAction extends AbstractAction{
//    private static final long serialVersionUID = 4402833394415561958L;

    @Override
    public void actionPerformed(ActionEvent evt){
      JOptionPane.showMessageDialog(ce, "Help not Available now!", "No Help function", JOptionPane.INFORMATION_MESSAGE);
    }
  }// end of HelpAction Class
  
  private void setZoomSelected(){
    switch(zoomPercent) {
      case 50:
        zoom50MenuItem.setSelected(true);
        break;
      case 75:
        zoom75MenuItem.setSelected(true);
        break;
      case 100:
        zoom100MenuItem.setSelected(true);
        break;
      case 125:
        zoom125MenuItem.setSelected(true);
        break;
      case 150:
        zoom150MenuItem.setSelected(true);
        break;
      default:
        zoom100MenuItem.setSelected(true);
    }
  }

}// end of CaseEditor Class
